package oop.ex2.main;

import java.util.ArrayList;


import oop.ex2.commands.BasicAssignmentCommand;
import oop.ex2.commands.Command;
import oop.ex2.commands.DivideAssignmentOp;
import oop.ex2.commands.InlineFunctionCommand;
import oop.ex2.commands.MinusAssignmentOp;
import oop.ex2.commands.OverloadCommand;
import oop.ex2.commands.PlusAssignmentOp;
import oop.ex2.commands.TimesAssignmentOp;
import oop.ex2.exceptions.EmptyExpression;
import oop.ex2.exceptions.ExpectedAtomicExpression;
import oop.ex2.exceptions.ExpectedBinaryOperation;
import oop.ex2.exceptions.TerminatingStringNotFound;
import oop.ex2.exceptions.TokenNotRecognized;
import oop.ex2.exceptions.UnrecognizedCommand;
import oop.ex2.exceptions.UnrecognizedVariable;
import oop.ex2.expression.ExpressionSolver;

/**
 * This class is in charge of taking a line of input from the user and passing it to the correct command type.
 * It first checks if the line is in a format recognized by any specialized commands. If not, then it attempts to construct
 * an expression out of it.
 * The line parser stores an internal state consisting of a variable table and a list of recognized functions and operators.
 * In this implementation, these are stored by holding an expression solver.
 * 
 * @author daniel_i_l
 *
 */
public class LineProcessor {
	private ExpressionSolver _expressionSolver;
	private ArrayList<Command> _commands;
	
	/**
	 * Construct a default line processor.
	 */
	public LineProcessor() {
		_expressionSolver = new ExpressionSolver();
		_commands = new ArrayList<Command>();
		addDefaultCommands();
	}
	
	/**
	 * Use the given line to execute a command.
	 * @param line The line to process.
	 * @throws UnrecognizedCommand if the line contains an unrecognized command.
	 * @throws EmptyExpression an empty expression was encountered.
	 * @throws ExpectedAtomicExpression if an atomic symbol was expected and not found.
	 * @throws ExpectedBinaryOperation  if a binary operation was expected and not found.
	 * @throws TerminatingStringNotFound  if the end of an sequence was expected and not found.
	 * @throws TokenNotRecognized if an unrecognized token was encountered.
	 * @throws UnrecognizedVariable if an unrecognized variable was referenced.
	 */
	public void processLine(String line) 
	throws TokenNotRecognized, EmptyExpression, ExpectedAtomicExpression, 
	ExpectedBinaryOperation, TerminatingStringNotFound, UnrecognizedVariable, UnrecognizedCommand
	{
		//find a command that fits
		//remove excess spaces
		line = line.trim();
		
		for (Command command : _commands)
		{
			if (command.executeCommand(line))
				return;
		}
		
		//the line must be an expression
		OutputFormatter.printOutput(_expressionSolver.calculateExpression(line));
	}
	
	private void addDefaultCommands()
	{
		_commands.add(new BasicAssignmentCommand(_expressionSolver));
		_commands.add(new PlusAssignmentOp(_expressionSolver));
		_commands.add(new MinusAssignmentOp(_expressionSolver));
		_commands.add(new TimesAssignmentOp(_expressionSolver));
		_commands.add(new DivideAssignmentOp(_expressionSolver));
		
		_commands.add(new OverloadCommand(_expressionSolver));
		
		_commands.add(new InlineFunctionCommand(_expressionSolver));
	}
}
